package main

import (
	"context"
	"crypto/rand"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"math/big"
	"net/http"
	"time"

	"github.com/go-redis/redis/v8"
)

var rdb *redis.Client
var setPort int
var redisAddr string
var showVersion bool
var versionDescription string = "1 新增CPU密集操作增加负载"

func init() {
	//解析用户指定的端口
	flag.IntVar(&setPort, "p", 9090, "set server port")
	//解析redis地址
	flag.StringVar(&redisAddr, "rdb", "localhost:6379", "set redis server addr")
	//展示版本和说明
	flag.BoolVar(&showVersion, "v", false, "print version info")
}

func main() {
	//处理命令行参数
	if commandArgHandle() {
		return
	}

	rdb = redis.NewClient(&redis.Options{
		Addr:     redisAddr,
		DB:       0,
		Password: "",
	})
	//结束运行后关闭链接
	defer rdb.Close()

	//注册路由
	http.HandleFunc("/save", handleSave)
	http.HandleFunc("/read", handleRead)

	//注册路由
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "welcome access me!\n")
	})

	addr := fmt.Sprintf(":%d", setPort)
	log.Printf("server is started, addr %s", addr)
	log.Fatal(http.ListenAndServe(addr, nil))

}

func commandArgHandle() (abort bool) {
	flag.Parse()

	//展示版本信息，直接返回true 中断下一步执行
	if showVersion {
		fmt.Printf("version: %s \n", versionDescription)
		return true
	}

	return
}

//handleSave 保存
func handleSave(w http.ResponseWriter, r *http.Request) {
	body := make([]byte, r.ContentLength)
	_, err := r.Body.Read(body)
	if err != io.EOF && err != nil {
		fmt.Fprintf(w, "error %s", err)
		return
	}
	v := make(map[string]interface{}, 0)
	err = json.Unmarshal(body, &v)
	if err != nil {
		fmt.Fprintf(w, "data format err: %s", v)
		return
	}

	if len(v) == 0 {
		fmt.Fprintf(w, "data is empty")
		return
	}

	ctx := context.Background()

	//保存数据
	for key, val := range v {
		rcmd := rdb.Set(ctx, key, val, 0)
		fmt.Println(rcmd)
	}

	fmt.Fprintf(w, "ok")
}

//handleRead 读取
func handleRead(w http.ResponseWriter, r *http.Request) {

	//故意设置一个高负载操作
	x := 0
	for i := 0; i < 200000000; i++ {
		x = x + 1
		x = x - 1
	}

	body := make([]byte, r.ContentLength)
	_, err := r.Body.Read(body)
	if err != io.EOF && err != nil {
		fmt.Fprintf(w, "error %s", err)
		return
	}
	var v []string
	err = json.Unmarshal(body, &v)
	if err != nil {
		fmt.Fprintf(w, "data format err: %s", v)
		return
	}

	if len(v) == 0 {
		fmt.Fprintf(w, "data is empty")
		return
	}

	ctx := context.Background()
	respData := make(map[string]string, 0)

	for _, reqKey := range v {
		respVal, err := rdb.Get(ctx, reqKey).Result()
		if err != nil || err == redis.Nil {
			continue
		} else {
			respData[reqKey] = respVal
		}
	}

	type Resp struct {
		Time    string
		Data    map[string]string
		RandNum int
	}

	n, _ := rand.Int(rand.Reader, big.NewInt(128))

	respObj := &Resp{
		Time:    time.Now().Format("2006-01-02 15:04:05"),
		Data:    respData,
		RandNum: n.BitLen(),
	}

	resp, err := json.Marshal(respObj)
	if err != nil {
		fmt.Fprintf(w, "fail")
	}

	w.Header().Add("Content-Type", "application/json")
	w.Write(resp)
}
